package mearth;
import java.io.Serializable;

import processing.core.PApplet;


public class GridNode implements Serializable {

	
	public static int nbrLeaves = 0;
	public static int nbrParents = 0;
	public static int nbrDisplayed = 0;
	
	byte paletteIdx;
	GridNode[] grid;


	
	public GridNode() {
		super();
		grid = null;
	}

	public GridNode partition(int px, int py, int pw, int ph, int[] p, int iw, GridImage.Palette palette){
		if(pw < 1 && ph < 1)
			return this;
		boolean partitionRequired = false;
		int argb = p[py * iw + px]; // color at top left pixel for this partition
		paletteIdx = palette.addColor(argb);
		for(int row = 0; row < ph; row++){
			int pn = (py + row) * iw + px;
			for(int col = 0; col < pw; col++){
				// If different colours then we will have to partition
				if(argb != p[pn++]){
					partitionRequired = true;
					break;
				}
			}
			if(partitionRequired)
				break;
		}
		if(partitionRequired){
			int pw0, pw1, ph0, ph1;
			pw1 = pw/2;
			pw0 = pw - pw1;
			ph1 = ph/2;
			ph0 = ph - ph1;
			int px0, px1, py0, py1;
			px0 = px;
			px1 = px0 + pw0;
			py0 = py;
			py1 = py0 + ph0;
			
			grid = new GridNode[] { null, null, null, null };
			nbrParents ++;
			if(pw1 == 0){
				grid[0] = new GridNode().partition(px0, py0, 1, ph0, p, iw, palette);
				grid[2] = new GridNode().partition(px0, py1, 1, ph1, p, iw, palette);
				return this;
			}
			if(ph1 == 0){
				grid[0] = new GridNode().partition(px0, py0, pw0, 1, p, iw, palette);
				grid[1] = new GridNode().partition(px1, py0, pw1, 1, p, iw, palette);
				return this;
			}
			grid[0] = new GridNode().partition(px0, py0, pw0, ph0, p, iw, palette);
			grid[1] = new GridNode().partition(px1, py0, pw1, ph0, p, iw, palette);
			grid[2] = new GridNode().partition(px0, py1, pw0, ph1, p, iw, palette);
			grid[3] = new GridNode().partition(px1, py1, pw1, ph1, p, iw, palette);
			return this;
		}
		nbrLeaves++;
		return this;
	}

	public NodeInfo smallestFit(int px, int py, int pw, int ph, int mx, int my, int mw, int mh){
		int pw0, pw1, ph0, ph1;
		pw1 = pw/2;
		pw0 = pw - pw1;
		ph1 = ph/2;
		ph0 = ph - ph1;
		int px0, px1, py0, py1;
		px0 = px;
		px1 = px0 + pw0;
		py0 = py;
		py1 = py0 + ph0;
		if(grid[0] != null && bb(px0, py0, pw0, ph0, mx, my, mw, mh))
			return grid[0].smallestFit(px0, py0, pw0, ph0, mx, my, mw, mh);
		
		if(grid[1] != null && bb(px1, py0, pw1, ph0, mx, my, mw, mh))
			return grid[1].smallestFit(px1, py0, pw1, ph0, mx, my, mw, mh);
		
		if(grid[2] != null && bb(px0, py1, pw0, ph1, mx, my, mw, mh))
			return grid[2].smallestFit(px0, py1, pw0, ph1, mx, my, mw, mh);
		
		if(grid[3] != null && bb(px1, py1, pw1, ph1, mx, my, mw, mh))
			return grid[3].smallestFit(px1, py1, pw1, ph1, mx, my, mw, mh);

		System.out.println("Fits: "+px+" "+py+" "+pw+" "+ph);
		return new NodeInfo(this, px, py, pw, ph);
	}
	
	public static boolean bb(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh){
		return (bx >= ax && bx + bw <= ax + aw && by >= ay && by + bh <= ay + ah);
	}


	public void display(PApplet app, int px, int py, int pw, int ph, GridImage.Palette palette){
		if(grid == null) {
			app.fill(palette.getColor(paletteIdx));
			app.rect(px, py, pw, ph);
			nbrDisplayed++;
		}
		else {
			int pw0, pw1, ph0, ph1;
			pw1 = pw/2;
			pw0 = pw - pw1;
			ph1 = ph/2;
			ph0 = ph - ph1;
			int px0, px1, py0, py1;
			px0 = px;
			px1 = px0 + pw0;
			py0 = py;
			py1 = py0 + ph0;
			if(grid[0] != null)
				grid[0].display(app, px0, py0, pw0, ph0, palette);
			if(grid[1] != null)
				grid[1].display(app, px1, py0, pw1, ph0, palette);
			if(grid[2] != null)
				grid[2].display(app, px0, py1, pw0, ph1, palette);
			if(grid[3] != null)
				grid[3].display(app, px1, py1, pw1, ph1, palette);
		}

	}
}
